<template>
  <form @submit.prevent="handleSubmit" class="dynamic-form">
    <DynamicFormItem v-for="field in fields" :key="field.name" :field="field" v-model="formData[field.name]"
      :errors="errors[field.name]" @validate="validateField" />

    <div class="form-actions">
      <button type="submit" :disabled="isSubmitting || hasErrors" class="submit-button">
        {{ isSubmitting ? '提交中...' : submitText }}
      </button>
      <button v-if="showReset" type="button" @click="resetForm" class="reset-button">
        重置
      </button>
    </div>
  </form>
</template>

<script lang="ts">
import { defineComponent, reactive, ref, computed, watch } from 'vue';
import DynamicFormItem from './DynamicFormItem.vue';
import type { FormField, FormData, SubmitHandler, ValidationRule, FormFieldType } from '../../types/dynamicForm';

export default defineComponent({
  name: 'DynamicForm',
  components: { DynamicFormItem },
  props: {
    fields: {
      type: Array as () => FormField[],
      required: true,
      validator: (value: FormField[]) => {
        return value.every(field => field.name && field.type && field.label);
      }
    },
    submitText: {
      type: String,
      default: '提交'
    },
    showReset: {
      type: Boolean,
      default: true
    },
    onSubmit: {
      type: Function as unknown as () => SubmitHandler,
      required: true
    }
  },
  setup(props, { emit }) {
    // 初始化表单数据
    const initFormData = () => {
      const data: FormData = {};
      props.fields.forEach(field => {
        data[field.name] = field.defaultValue ?? getDefaultValue(field.type);
      });
      return data;
    };

    const getDefaultValue = (type: FormFieldType): any => {
      switch (type) {
        case 'checkbox': return [];
        case 'switch': return false;
        case 'slider': return 0;
        default: return '';
      }
    };

    const formData = reactive<FormData>(initFormData());
    const errors = reactive<Record<string, string[]>>({});
    const isSubmitting = ref(false);
    const touchedFields = ref<Set<string>>(new Set());

    // 计算是否有错误
    const hasErrors = computed(() => {
      return Object.values(errors).some(errorList => errorList.length > 0);
    });

    // 验证单个字段
    const validateField = (fieldName: string) => {
      touchedFields.value.add(fieldName);
      const field = props.fields.find(f => f.name === fieldName);
      if (!field) return;

      const value = formData[fieldName];
      const fieldErrors: string[] = [];

      // 处理必填验证
      if (field.required) {
        const requiredRule = {
          validator: (val: any) => {
            if (typeof val === 'string') return val.trim() !== '';
            if (Array.isArray(val)) return val.length > 0;
            return val !== undefined && val !== null;
          },
          message: `${field.label}为必填项`
        };
        if (!requiredRule.validator(value)) {
          fieldErrors.push(requiredRule.message);
        }
      }

      // 处理自定义验证规则
      if (field.validation) {
        field.validation.forEach(rule => {
          if (!rule.validator(value)) {
            fieldErrors.push(rule.message);
          }
        });
      }

      errors[fieldName] = fieldErrors;
    };

    // 验证整个表单
    const validateForm = () => {
      props.fields.forEach(field => {
        validateField(field.name);
      });
      return !hasErrors.value;
    };

    // 提交表单
    const handleSubmit = async () => {
      if (!validateForm()) return;

      isSubmitting.value = true;
      try {
        await props.onSubmit(formData);
      } catch (error) {
        console.error('表单提交错误:', error);
      } finally {
        isSubmitting.value = false;
      }
    };

    // 重置表单
    const resetForm = () => {
      Object.assign(formData, initFormData());
      Object.keys(errors).forEach(key => {
        errors[key] = [];
      });
      touchedFields.value = new Set();
    };

    // 监听表单数据变化，自动验证已触摸的字段
    watch(formData, (newData) => {
      touchedFields.value.forEach(fieldName => {
        validateField(fieldName);
      });
    }, { deep: true });

    return {
      formData,
      errors,
      isSubmitting,
      hasErrors,
      validateField,
      handleSubmit,
      resetForm
    };
  }
});
</script>

<style scoped>
.dynamic-form {
  /* max-width: 600px; */
  width: 100%;
  margin: 0 auto;
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.form-actions {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin-top: 20px;
}

.submit-button {
  padding: 10px 20px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.submit-button:hover {
  background-color: #45a049;
}

.submit-button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.reset-button {
  padding: 10px 20px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.reset-button:hover {
  background-color: #d32f2f;
}
</style>